package sk.stuba.fiit.foo07.genex.gui;

import java.sql.SQLException;
import java.util.ArrayList;

import javax.swing.ImageIcon;
import javax.swing.table.AbstractTableModel;

import sk.stuba.fiit.foo07.genex.beans.Category;
import sk.stuba.fiit.foo07.genex.beans.Question;
import sk.stuba.fiit.foo07.genex.dao.CategoryDao;
import sk.stuba.fiit.foo07.genex.dao.QuestionDao;
import sk.stuba.fiit.foo07.genex.dao.QuestionTypeDao;
import sk.stuba.fiit.foo07.genex.exceptions.QuestionInCategoryException;

public class GenexTableModel extends AbstractTableModel {

    /**
     * 
     */
    private static final long serialVersionUID = -5823071225893042256L;

    private int columnCount = 6;
    private String[] columnNames = null;

    private Category actualCat;
    private ImageIcon catIcon;
    private ImageIcon qIcon;
    private CategoryDao catDao;
    private QuestionDao qDao;
    private QuestionTypeDao qtDao;
    ArrayList<Category> categories;
    ArrayList<Question> questions;
    private ArrayList<Object> copiedObjects;
    private Category cutFromCategory;

    public GenexTableModel(ImageIcon catIcon, ImageIcon qIcon,
            CategoryDao catDao, QuestionDao qDao, QuestionTypeDao qtDao) {
        this.catIcon = catIcon;
        this.qIcon = qIcon;
        this.catDao = catDao;
        this.qDao = qDao;
        this.qtDao = qtDao;
        //TODO 
        //osetrit
        try {
            this.actualCat = catDao.getRootCategories().get(0);
        } catch (Exception e) {
        }
        actualizeContent();

        initColumnNames();
    }

    @Override
    public void fireTableDataChanged() {
        actualizeContent();
        super.fireTableDataChanged();
    }

    public void actualizeContent() {
        try {
            categories = catDao.getCategoriesByParentID(actualCat
                    .getCategoryID());

            questions = qDao
                    .getQuestionsByCategoryID(actualCat.getCategoryID());

        } catch (Exception e) {
        }
    }

    public void setActualCategory(Category newCat) {
        if (newCat == null)
            return;
        actualCat = newCat;
        this.fireTableDataChanged();
    }

    public Category getActualCategory() {
        return actualCat;
    }

    public void initColumnNames() {
        columnNames = new String[columnCount];

        columnNames[0] = new String("");
        columnNames[1] = new String("Otázka");
        columnNames[2] = new String("Typ");
        columnNames[3] = new String("Náročnosť");
        columnNames[4] = new String("Posledná úprava");
        columnNames[5] = new String("Odvodená");
    }

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return categories.size() + questions.size();
    }

    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        switch (col) {
        // ikona
        case 0:
            return row < categories.size() ? catIcon : qIcon;

            // text otazky || nazov kategorie
        case 1:
            return row < categories.size() ? categories.get(row) : questions
                    .get(row - categories.size());

            // typ
        case 2:
            if (row < categories.size()) {
                return "DIR";
            }
            //TODO
            //pozor vynimky
            String qt = null;
            try {
                qt = qtDao.getQuestionTypeByQuestionID(
                        questions.get(row - categories.size()).getQuestionID())
                        .getName();

            } catch (Exception e) {
            }
            if ("Single choice".equalsIgnoreCase(qt))
                return "S";
            else if ("Multi choice".equalsIgnoreCase(qt))
                return "M";
            else if ("True/False".equalsIgnoreCase(qt))
                return "TF";
            else if ("Fill in".equalsIgnoreCase(qt))
                return "F";
            else if ("Essay".equalsIgnoreCase(qt))
                return "E";
            else
                return "Un";

            // narocnost
        case 3:
            return row < categories.size() ? new Integer(-1) : questions.get(
                    row - categories.size()).getDifficulty();

            // last update
        case 4:
            return row < categories.size() ? categories.get(row)
                    .getLastUpdate() : questions.get(row - categories.size())
                    .getLastUpdate();
        case 5:

            return row < categories.size() ? "---" : questions.get(
                    row - categories.size()).getDerivedFromID() == null ? "Nie"
                    : "Áno";
        }

        return "undefined";
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return false;
    }

    public Object getValue(int row) {
        if (row < categories.size())
            return categories.get(row);
        else
            return questions.get(row - categories.size());
    }

    public void deleteItems(int[] selIndices) {
        for (int i = 0; i < selIndices.length; i++) {
            Object item = getValue(selIndices[i]);
            try {
                if (item instanceof Category) {
                    Category c = (Category) item;
                    if (c.getName().equals("Kôš")
                            || c.getName().equals("Konflikty")) {
                        continue;
                    }
                    catDao.deleteCategory((Category) item);
                } else {
                    qDao.deleteQuestionFromCategory((Question) item, actualCat);
                }
            } catch (QuestionInCategoryException e) {
                // TODO notify user that category is not empty
                deleteCategory((Category) item);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //TODO there should be other exceptions (PictureInPictureQuestionException)
        }

        fireTableDataChanged();
    }

    private void deleteCategory(Category c) {
        try {
            if (c.getName().equals("Kôš") || c.getName().equals("Konflikty"))
                return;
            try {

                ArrayList<Question> qs = qDao.getQuestionsByCategoryID(c
                        .getCategoryID());
                for (Question q : qs) {
                    qDao.deleteQuestionFromCategory(q, c);
                }

                ArrayList<Category> children = catDao.getCategoriesByParentID(c
                        .getCategoryID());
                for (Category cat : children) {
                    deleteCategory(cat);
                }

                catDao.deleteCategory(c);
            } catch (QuestionInCategoryException e) {
                //toto by uz nemalo nastat pretoze z kategorie sme uz udstranili aj otaky aj podkategorie
                e.printStackTrace();
            }
            categories.remove(c);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void copyData(int[] selIndices) {
        copiedObjects = new ArrayList<Object>(selIndices.length);
        for (int i = 0; i < selIndices.length; i++) {
            copiedObjects.add(getValue(selIndices[i]));
        }
        cutFromCategory = null;
    }

    public void cutData(int[] selIndices) {
        copyData(selIndices);
        cutFromCategory = actualCat;
    }

    public void pasteData() throws SQLException {
        if (copiedObjects == null)
            return;
        for (Object o : copiedObjects) {
            if (o instanceof Question) {
                Question q = (Question) o;
                qDao.copyQuestion(q.getQuestionID(), actualCat.getCategoryID());
                if (cutFromCategory != null) {
                    qDao.deleteQuestionFromCategory(q, cutFromCategory);
                }
            } else {
                Category c = (Category) o;
                Integer newID = catDao.copyCategory(c.getCategoryID(),
                        actualCat);
                if (cutFromCategory != null) {
                    deleteCategory(c);
                }
                c.setCategoryID(newID);
            }
        }
        if (cutFromCategory != null) {
            fireTableDataChanged();
        }
    }
}
